﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SIEGate.Core;
using SIEGate.Core.Measurements;
using SIEGate.Core.Measurements.Values;
using SIEGate.Core.MessageBusses;

namespace SIEGateCoreTest.MessageBusTests
{
    [TestClass]
    public class messagebusperform
    {
        ChannelMessageBus messageBus;

        [TestInitialize]
        public void TestsInitialize()
        {
            this.messageBus = new ChannelMessageBus(2 << 11);
        }
        [TestMethod]
        public void doperform()
        {
            IMessageBusProxy mbp = messageBus.GetProxy("foo");
            IMessageBusProxy mbp2 = messageBus.GetProxy("bar");
            bool prodrun, consrun;
            prodrun = true;
            consrun = true;
            long countsent = 0;
            long countrecv = 0;

            Guid g1 = Guid.NewGuid();
            HashSet<Guid> pubs = new HashSet<Guid>() { g1, Guid.NewGuid(), Guid.NewGuid() };
            mbp.Publish(pubs);
            mbp2.Subscribe(new HashSet<Guid>() { g1 });
            Task prod = new Task(() =>
            {
                Random rng = new Random();
                Thread.Sleep(25000);
                while (prodrun)
                {
                    IMeasurement m = new Measurement(g1, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                      new StringValue(rng.Next().ToString()));
                    mbp.Send(m);
                    Thread.Sleep(100);
                    countsent++;
                }
                mbp.Send(new Measurement(g1, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                    new StringValue("stop")));
                countsent++;
            });

            Task<int> cons = new Task<int>(() =>
            {
                int count = 0;
                while (consrun)
                {
                    IMeasurement[] recv = mbp2.Recv();
                    count += recv.Length;
                    foreach (IMeasurement M in recv)
                    {
                        countrecv++;
                        if (M.Value.GetRaw() == "stop") consrun = false;
                    }

                }
                return count;
            });
            cons.Start();
            Thread.Sleep(10);
            prod.Start();
            Thread.Sleep(30000);
            prodrun = false;

            cons.Wait();
            prod.Wait();
            Assert.AreEqual(countsent, countrecv);
        }
        [TestMethod]
        public void doperform2prods()
        {
            IMessageBusProxy mbp = messageBus.GetProxy("foo");
            IMessageBusProxy mbp2 = messageBus.GetProxy("bar");
            IMessageBusProxy mbp3 = messageBus.GetProxy("baz");

            bool prodrun, consrun;
            prodrun = true;
            consrun = true;

            long countsent1 = 0;
            long countsent2 = 0;
            long countrecv = 0;

            Guid g1 = Guid.NewGuid();
            Guid g2 = Guid.NewGuid();

            HashSet<Guid> pubs = new HashSet<Guid>() { g1, Guid.NewGuid(), Guid.NewGuid() };
            mbp.Publish(pubs);
            mbp3.Publish(new HashSet<Guid>() { g2, Guid.NewGuid() });
            mbp2.Subscribe(new HashSet<Guid>() { g1, g2 });
            Task prod = new Task(() =>
            {
                Random rng = new Random();
                while (prodrun)
                {
                    IMeasurement m = new Measurement(g1, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                      new StringValue(rng.Next().ToString()));
                    mbp.Send(m);
                    Thread.Sleep(100);
                    countsent1++;
                }
                mbp.Send(new Measurement(g1, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                    new StringValue("stop")));
            });

            Task prod2 = new Task(() =>
            {
                Random rng = new Random();
                while (prodrun)
                {
                    IMeasurement m = new Measurement(g2, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                      new StringValue(rng.Next().ToString()));
                    mbp3.Send(m);
                    countsent2++;
                    Thread.Sleep(100);
                }
                mbp3.Send(new Measurement(g2, new GSF.Ticks(), new SIEGate.Core.Legacy.MeasurementStateFlags(),
                    new StringValue("stop")));
            });

            Task<int> cons = new Task<int>(() =>
            {
                while (consrun)
                {
                    IMeasurement[] recv = mbp2.Recv();
                    countrecv += recv.Length;
                    foreach (IMeasurement M in recv)
                    {
                        if (M.Value.GetRaw() == "stop") consrun = false;
                    }

                }
                return (int)countrecv;
            });
            cons.Start();
            Thread.Sleep(10);
            prod.Start();
            Thread.Sleep(40);
            prod2.Start();
            Thread.Sleep(30000);
            prodrun = false;

            cons.Wait();
            prod.Wait();
            prod2.Wait();
            Assert.AreEqual(1.0, ((double)countrecv) / ((double)countsent1 + countsent2), .05);
        }

        [TestMethod]
        public void emptypubs()
        {
            IMessageBusProxy mbp = messageBus.GetProxy("foo");
            mbp.Subscribe(new HashSet<Guid>() {Guid.NewGuid()});
                bool run = true;
            int recvcount = 0;
            Random RNG = new Random();
            Task theLoop = new Task(() =>
            {
                while (run)
                {
                    int x = 2 * (RNG.Next() + 55) / 3;
                    IMeasurement[] res = mbp.Recv();
                    recvcount += res.Length;
                }
            });

            theLoop.Start();
            Thread.Sleep(30000);
            run = false;
            theLoop.Wait();

            Assert.AreEqual(0, recvcount);
        }
    }
}
